from django.views.generic import TemplateView
from accounts.models import StudentSurvey
from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Bar, Pie, HeatMap
from django.db.models import Avg, Count, Sum, Max
import pandas as pd
import numpy as np


class BasicStatsView(TemplateView):
    def __init__(self):
        self.model = StudentSurvey

    template_name = 'charts/basic_stats.html'

    def get_basic_statistics(self):
        """获取基本统计数据"""
        surveys = self.model.objects.all()

        # 统计总体数据
        stats = {
            'total_count': surveys.count(),
            'avg_age': surveys.aggregate(Avg('age'))['age__avg'],
            'avg_friends': surveys.aggregate(Avg('friends'))['friends__avg'],
        }

        # 计算最受欢迎的活动类型
        activity_fields = [
            'basketball', 'football', 'soccer', 'softball', 'volleyball',
            'swimming', 'baseball', 'tennis', 'sports', 'dance', 'band',
            'marching', 'music', 'rock'
        ]

        activity_names = {
            'basketball': '篮球', 'football': '足球', 'soccer': '英式足球',
            'softball': '垒球', 'volleyball': '排球', 'swimming': '游泳',
            'baseball': '棒球', 'tennis': '网球', 'sports': '体育运动',
            'dance': '舞蹈', 'band': '乐队', 'marching': '军乐队',
            'music': '音乐', 'rock': '摇滚音乐'
        }

        # 统计每种活动的平均兴趣度
        activity_avg = {}
        for field in activity_fields:
            avg = surveys.exclude(**{f"{field}": 0}).aggregate(Avg(field))[f"{field}__avg"] or 0
            activity_avg[field] = avg

        # 找出最受欢迎的活动
        most_popular = max(activity_avg.items(), key=lambda x: x[1])
        stats['most_popular_activity'] = activity_names.get(most_popular[0], most_popular[0])

        # 找出最高兴趣度
        highest_interest = max(activity_avg.values())
        stats['highest_interest_score'] = highest_interest

        return stats

    # 统计年龄分布图（柱状图）
    def get_age_distribution(self):
        surveys = self.model.objects.all()

        # 定义年龄段
        age_ranges = ['小于18岁', '18-25岁', '26-35岁', '36-45岁', '大于45岁']
        age_counts = [0, 0, 0, 0, 0]

        # 统计各年龄段人数
        for survey in surveys:
            age = survey.age
            if age < 18:
                age_counts[0] += 1
            elif 18 <= age <= 25:
                age_counts[1] += 1
            elif 26 <= age <= 35:
                age_counts[2] += 1
            elif 36 <= age <= 45:
                age_counts[3] += 1
            else:
                age_counts[4] += 1

        # 创建年龄分布柱状图
        age_bar = (
            Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='350px'))
            .add_xaxis(age_ranges)
            .add_yaxis(
                "人数",
                age_counts,
                itemstyle_opts=opts.ItemStyleOpts(
                    color="#5470c6",
                    border_radius=[7, 7, 7, 7]
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="年龄分布"),
                xaxis_opts=opts.AxisOpts(name="年龄段"),
                yaxis_opts=opts.AxisOpts(name="人数"),
                tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow")
            )
            .set_series_opts(
                label_opts=opts.LabelOpts(is_show=True, position="top")
            )
        )

        return age_bar.render_embed()

    # 性别图（饼图）
    def get_gender_distribution(self):
        surveys = self.model.objects.all()

        # 统计性别分布
        gender_count = {'男': 0, '女': 0, '其他': 0}

        for survey in surveys:
            if survey.gender == 'M':
                gender_count['男'] += 1
            elif survey.gender == 'F':
                gender_count['女'] += 1
            else:
                gender_count['其他'] += 1

        # 将统计数据转为饼图需要的格式
        gender_data = [(key, value) for key, value in gender_count.items() if value > 0]

        # 创建性别分布饼图
        gender_pie = (
            Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='350px'))
            .add(
                "性别分布",
                gender_data,
                radius=["40%", "70%"],
                center=["50%", "50%"],
                rosetype="radius",
                label_opts=opts.LabelOpts(
                    formatter="{b}: {c} ({d}%)"
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="性别分布"),
                legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
                tooltip_opts=opts.TooltipOpts(
                    trigger="item",
                    formatter="{a} <br/>{b}: {c} ({d}%)"
                )
            )
        )

        return gender_pie.render_embed()

    # 毕业年份分布
    def get_graduation_year_distribution(self):
        surveys = self.model.objects.all()

        # 获取所有毕业年份并按年份分组统计
        grad_years = surveys.values('gradyear').annotate(count=Count('gradyear')).order_by('gradyear')

        # 提取数据
        years = [item['gradyear'] for item in grad_years]
        counts = [item['count'] for item in grad_years]

        # 创建毕业年份分布柱状图
        grad_bar = (
            Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='350px'))
            .add_xaxis(years)
            .add_yaxis(
                "人数",
                counts,
                itemstyle_opts=opts.ItemStyleOpts(
                    color="#91cc75",
                    border_radius=[7, 7, 0, 0]
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="毕业年份分布"),
                xaxis_opts=opts.AxisOpts(
                    name="毕业年份",
                    type_="category",
                    axislabel_opts=opts.LabelOpts(rotate=30)
                ),
                yaxis_opts=opts.AxisOpts(name="人数"),
                tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="shadow"),
                datazoom_opts=[
                    opts.DataZoomOpts(range_start=0, range_end=100),
                    opts.DataZoomOpts(type_="inside")
                ]
            )
            .set_series_opts(
                label_opts=opts.LabelOpts(is_show=True, position="top", rotate=90)
            )
        )

        return grad_bar.render_embed()

    # 社交活跃度饼图
    def get_social_activity_distribution(self):
        surveys = self.model.objects.all()

        # 定义社交活跃度范围
        ranges = [
            ('极少社交 (0-10)', 0, 10),
            ('较少社交 (11-30)', 11, 30),
            ('中等社交 (31-60)', 31, 60),
            ('活跃社交 (61-100)', 61, 100),
            ('高度社交 (>100)', 101, 999)
        ]

        # 统计各范围的人数
        counts = []
        for name, min_val, max_val in ranges:
            count = surveys.filter(friends__gte=min_val, friends__lte=max_val).count()
            if count > 0:
                counts.append((name, count))

        # 创建社交活跃度饼图
        social_pie = (
            Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='350px'))
            .add(
                "社交活跃度",
                counts,
                radius=["40%", "70%"],
                center=["50%", "50%"],
                label_opts=opts.LabelOpts(
                    formatter="{b}: {c}人"
                )
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="社交活跃度分布"),
                legend_opts=opts.LegendOpts(
                    orient="vertical",
                    pos_top="center",
                    pos_left="2%",
                    item_width=15,
                    item_height=10
                ),
                tooltip_opts=opts.TooltipOpts(
                    trigger="item",
                    formatter="{a} <br/>{b}: {c}人 ({d}%)"
                )
            )
        )

        return social_pie.render_embed()

    # 兴趣分布热点图
    def get_interest_heatmap(self):
        surveys = self.model.objects.all()

        # 定义要分析的兴趣类别
        interest_categories = [
            ['体育活动', ['basketball', 'football', 'soccer', 'softball', 'volleyball', 'swimming', 'baseball', 'tennis', 'sports']],
            ['艺术音乐', ['dance', 'band', 'marching', 'music', 'rock']],
            ['宗教活动', ['god', 'church', 'jesus', 'bible']],
            ['时尚购物', ['hair', 'dress', 'mall', 'shopping', 'clothes', 'hollister', 'abercrombie']],
            ['个性特征', ['cute', 'sexy', 'hot', 'kissed']],
            ['风险行为', ['drunk', 'drugs', 'death', 'die']]
        ]

        # 按照性别和年龄段分类
        gender_labels = ['男性', '女性']
        age_ranges = ['<18岁', '18-25岁', '26-35岁', '36-45岁', '>45岁']

        # 准备热力图数据
        heatmap_data = []
        y_index = 0

        # 遍历性别
        for gender_code, gender_label in zip(['M', 'F'], gender_labels):
            gender_surveys = surveys.filter(gender=gender_code)

            # 遍历年龄段
            for age_idx, age_range in enumerate(age_ranges):
                # 确定年龄范围
                if age_idx == 0:
                    age_filter = gender_surveys.filter(age__lt=18)
                elif age_idx == 1:
                    age_filter = gender_surveys.filter(age__gte=18, age__lte=25)
                elif age_idx == 2:
                    age_filter = gender_surveys.filter(age__gte=26, age__lte=35)
                elif age_idx == 3:
                    age_filter = gender_surveys.filter(age__gte=36, age__lte=45)
                else:
                    age_filter = gender_surveys.filter(age__gt=45)

                # 如果该分类下没有数据，则跳过
                if age_filter.count() == 0:
                    continue

                # 遍历兴趣类别
                for x_index, (category, fields) in enumerate(interest_categories):
                    # 计算该人群在该兴趣类别的平均兴趣度
                    total_interest = 0
                    total_count = 0

                    for field in fields:
                        # 排除未填写的0值数据
                        non_zero = age_filter.exclude(**{field: 0})
                        if non_zero.exists():
                            avg = non_zero.aggregate(Avg(field))[f"{field}__avg"] or 0
                            total_interest += avg
                            total_count += 1

                    # 计算该类别的平均兴趣度
                    avg_interest = round(total_interest / max(1, total_count), 2)

                    label = f"{gender_label}-{age_range}"
                    heatmap_data.append([x_index, y_index, avg_interest])

                y_index += 1

        # 创建Y轴标签
        y_labels = []
        for gender in gender_labels:
            for age in age_ranges:
                y_labels.append(f"{gender}-{age}")

        # 只保留数据中存在的标签
        y_labels = y_labels[:y_index]

        # 创建X轴标签
        x_labels = [category for category, _ in interest_categories]

        # 创建热力图
        heatmap = (
            HeatMap(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width='100%', height='400px'))
            .add_xaxis(x_labels)
            .add_yaxis(
                "平均兴趣度",
                y_labels,
                heatmap_data,
                label_opts=opts.LabelOpts(is_show=True, formatter="{c}"),
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="不同人群的兴趣分布热点图"),
                visualmap_opts=opts.VisualMapOpts(
                    min_=0,
                    max_=5,
                    is_calculable=True,
                    orient="vertical",
                    pos_left="right",
                    pos_bottom="center",
                    range_color=["#d7e3bc", "#7acf82", "#31a354", "#116423"],
                ),
                tooltip_opts=opts.TooltipOpts(
                    formatter="{a} <br/>{b} 对 {c} 的平均兴趣度: {d}"
                ),
            )
        )

        return heatmap.render_embed()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # 获取基本统计数据
        stats = self.get_basic_statistics()
        context.update(stats)

        # 添加各种图表
        context['gender_chart'] = self.get_gender_distribution()
        context['age_chart'] = self.get_age_distribution()
        context['graduation_chart'] = self.get_graduation_year_distribution()
        context['social_chart'] = self.get_social_activity_distribution()
        context['interest_heatmap'] = self.get_interest_heatmap()

        # 设置导航标识
        context['navname'] = 'basic'
        context['total_participants'] = stats['total_count']

        return context
